package client.jobs;

import client.MapleBuffStat;
import client.MapleCharacter;
import client.MapleClient;
import client.anticheat.CheatingOffense;
import client.jobs.job.AttackType;
import client.skills.Skill;
import client.skills.SkillFactory;
import constants.ServerConstants;
import constants.SkillConstants;
import constants.skills.圣骑士;
import constants.skills.夜光;
import handling.channel.handler.AttackInfo;
import handling.world.WorldBroadcastService;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import server.MapleStatEffect;
import tools.MaplePacketCreator;

/**
 * @Author dwang
 * @Description 校验相关的方法
 * @create 2022/5/24 10:48
 * @Modified By:
 */
public class JobCheckUtil {
    private static final Logger log = LogManager.getLogger(JobCheckUtil.class.getName());

    /**
     * 校验攻击
     * @param chr
     * @param c
     * @param attack
     * @param attackType
     * @return
     */
   public static boolean checkAttack(MapleCharacter chr, MapleClient c, AttackInfo attack, AttackType attackType ) {
        String showType = "";
        switch (attackType) {
            case CLOSE_RANGE:
                showType = "近距离攻击";
                break;
            case RANGE:
                showType = "远距离攻击";
                break;
            case MAGIC:
                showType = "魔法攻击";
                break;
        }


        if (attack == null) {
            if (chr.isShowPacket()) {
                chr.dropDebugMessage(3, "[" + showType + "] 攻击封包解析返回为空.");
            }
            c.announce(MaplePacketCreator.enableActions());
            return false;
        }

        if (SkillFactory.isBlockedSkill(attack.skillId)) {
            chr.dropMessage(5, "由于<" + SkillFactory.getSkillName(attack.skillId) + ">技能数据异常,暂未开放使用.");
            c.announce(MaplePacketCreator.enableActions());
            return false;
        }

        if (attack.skillId != 0 && chr.isShowPacket()) {
            chr.dropDebugMessage(1, "[" + showType + "] 技能: " + SkillFactory.getSkillName(attack.skillId) + "(" + attack.skillId + ") 技能等级: " + attack.skllv + " 攻击次数: " + attack.numAttacked + " 伤害次数: " + attack.numDamage);
        }
        return true;
    }

    /**
     * 校验技能
     * @param attack
     * @param type
     * @param chr
     * @param c
     * @param energy
     * @return
     */
    public static CheckSkillEffectInfo checkSkillAndEffect(AttackInfo attack, AttackType type, MapleCharacter chr, MapleClient c, boolean energy) {
        String showType = "";
        Skill skill = null;
        int skillLevel = -1;
        switch (type) {
            case CLOSE_RANGE:
                int linkSkillId = SkillConstants.getLinkedAttackSkill(attack.skillId);
                skill = SkillFactory.getSkill(linkSkillId);
                skillLevel = chr.getTotalSkillLevel(linkSkillId);
                showType = "近距离攻击";
                break;
            case RANGE:
                showType = "远距离攻击";
                break;
            case MAGIC:
                showType = "魔法攻击";
                break;
        }


        if (skill == null || (SkillConstants.is天使祝福戒指(attack.skillId) && (chr.getStat().equippedSummon % 10000) != (attack.skillId % 10000))) {
            c.announce(MaplePacketCreator.enableActions());
            return new CheckSkillEffectInfo(Boolean.FALSE, skill, skillLevel, null);
        }
        MapleStatEffect effect = attack.getAttackEffect(chr, skillLevel, skill);

        if (effect == null || skillLevel < 0) {
            chr.dropDebugMessage(2, "[" + showType + "] 技能: " + SkillFactory.getSkillName(attack.skillId) + "(" + attack.skillId + ") 技能数据出现错误.");
            Skill.log.error(showType + "效果为空 玩家[" + chr.getName() + " 职业: " + chr.getJob() + "] 使用技能: " + skill.getId() + " - " + skill.getName() + " 技能等级: " + skillLevel);
            c.announce(MaplePacketCreator.enableActions());
            return new CheckSkillEffectInfo(Boolean.FALSE, skill, skillLevel, null);
        }


        if (!applyAttackCooldown(effect, chr, attack.skillId, skill.isChargeSkill(), false, energy)) {
            return new CheckSkillEffectInfo(Boolean.FALSE, skill, skillLevel, null);
        }
        return new CheckSkillEffectInfo(Boolean.TRUE, skill, skillLevel, effect);

    }
    private static boolean applyAttackCooldown(MapleStatEffect effect, MapleCharacter chr, int skillid, boolean isChargeSkill, boolean isBuff, boolean energy) {
        int cooldownTime = effect.getCooldown(chr);
        if (cooldownTime > 0) {
            if (chr.skillisCooling(skillid) && !isChargeSkill && !isBuff && !SkillConstants.isNoDelaySkill(skillid)) {
                chr.dropMessage(5, "技能由于冷却时间限制，暂时无法使用。");
                chr.send(MaplePacketCreator.enableActions());
                return false;
            } else {
                if (chr.isAdmin() || energy) {
                    if (isBuff) {
                        chr.dropDebugMessage(2, "[技能冷却] 为GM消除技能冷却时间, 原技能冷却时间:" + cooldownTime + "秒");
                    }
                } else {
                    chr.addCooldown(skillid, System.currentTimeMillis(), cooldownTime * 1000);
                    chr.send(MaplePacketCreator.skillCooldown(SkillConstants.getLinkedAttackSkill(skillid), cooldownTime));
                }
            }
        }
        return true;
    }

    /**
     * 检查特殊技能和地图
     * @param player
     * @param attack
     * @param effect
     * @return
     */
    public static Boolean checkSkillInSpecialSpace(MapleCharacter player, AttackInfo attack, MapleStatEffect effect) {
        if (SkillConstants.isMulungSkill(attack.skillId)) {
            if (player.getMapId() / 10000 != 92502) {
                //AutobanManager.getInstance().autoban(player.getClient(), "Using Mu Lung dojo skill out of dojo maps.");
                return Boolean.FALSE;
            } else {
                if (player.getMulungEnergy() < 10000) {
                    return Boolean.FALSE;
                }
                player.mulung_EnergyModify(false);
            }
        } else if (SkillConstants.isPyramidSkill(attack.skillId)) {
            if (player.getMapId() / 1000000 != 926) {
                //AutobanManager.getInstance().autoban(player.getClient(), "Using Pyramid skill outside of pyramid maps.");
                return Boolean.FALSE;
            } else {
                if (player.getPyramidSubway() == null || !player.getPyramidSubway().onSkillUse(player)) {
                    return Boolean.FALSE;
                }
            }
        } else if (SkillConstants.isInflationSkill(attack.skillId)) {
            if (player.getBuffedValue(MapleBuffStat.巨人药水) == null) {
                return Boolean.FALSE;
            }

        }
        return Boolean.TRUE;
    }

    public static boolean checkApplyAttackUser(MapleCharacter player, AttackInfo attack, Skill theSkill) {
        //如果玩家死亡
        if (!player.isAlive() || player.isBanned()) {
            player.getCheatTracker().registerOffense(CheatingOffense.ATTACKING_WHILE_DEAD, "操作者已死亡.");
            return false;
        }
        //大于100的就检测攻击时间
        if (attack.real && SkillConstants.getAttackDelay(attack.skillId, theSkill) >= 50) {
            player.getCheatTracker().checkAttack(attack.skillId, attack.lastAttackTickCount);
        }
        return  true;
    }


    /**
     * 魔法攻击次数
     * @param player
     * @param attack
     * @param mobCount
     * @param attackCount
     * @return
     */
    public static boolean checkMagicAttackCount(MapleCharacter player, AttackInfo attack, int mobCount, int attackCount) {
        if (attack.numDamage > attackCount || (attack.numAttacked > mobCount && attack.skillId != 夜光.绝对死亡)) {
            if (player.isShowPacket()) {
                player.dropDebugMessage(3, "[攻击信息] 魔法攻击次数出错 解析攻击次数:" + attack.numDamage + " 实际次数:" + attackCount + " 解析怪物数量:" + attack.numAttacked + " 实际怪物数量:" + mobCount);
            }
            player.getCheatTracker().registerOffense(CheatingOffense.MISMATCHING_BULLETCOUNT, "异常的攻击次数.");
            log.info("[作弊] " + player.getName() + " 魔法攻击次数异常  解析攻击次数:" + attack.numDamage + " 实际次数:" + attackCount + " 解析怪物数量:" + attack.numAttacked + " 实际怪物数量:" + mobCount);
            if (ServerConstants.isShowGMMessage()) {
                WorldBroadcastService.getInstance().broadcastGMMessage(MaplePacketCreator.serverNotice(6, "[GM消息] " + player.getName() + " ID: " + player.getId() + " (等级 " + player.getLevel() + ") 魔法攻击次数异常。attack.hits " + attack.numDamage + " attackCount " + attackCount + " attack.targets " + attack.numAttacked + " MobCount " + mobCount + " 技能ID " + attack.skillId));
            }
            return false;
        }

        if (attack.numDamage > 0 && attack.numAttacked > 0) {
            if (!player.getStat().checkEquipDurabilitys(player, -1)) { //i guess this is how it works ?
                player.dropMessage(5, "An item has run out of durability but has no inventory room to go to.");
                return false;
            }
        }
        return  true;
    }


    /**
     * 检查物理攻击次数
     * @param player
     * @param attack
     * @param effect
     * @param mobCount
     * @param attackCount
     * @return
     */
    public static boolean checkAttackCount(MapleCharacter player, AttackInfo attack, MapleStatEffect effect, int mobCount, int attackCount) {

        if (attack.numAttacked > mobCount && attack.skillId != 圣骑士.万佛归一破) { // Must be done here, since NPE with normal atk
            player.getCheatTracker().registerOffense(CheatingOffense.MISMATCHING_BULLETCOUNT, "异常的攻击次数.");
            if (player.isShowPacket()) {
                player.dropMessage(-5, "物理怪物数量检测 => 封包解析次数: " + attack.numAttacked + " 服务端设置次数: " + effect.getMobCount(player));
            }
            return false;
        }

        /* 检测技能是否为正常的攻击次数 ： 在此处定义的技能将不会被检测 */
        boolean useAttackCount = !SkillConstants.isNoCheckAttackSkill(attack.skillId);

        /* 检测伤害次数是否大于攻击次数 */
        if (attack.numDamage > attackCount) {
            if (useAttackCount) {
                if (player.isShowPacket()) {
                    player.dropDebugMessage(3, "[攻击信息] 物理攻击次数出错 技能ID:" + attack.skillId + " 封包解析次数:" + attack.numDamage + " 实际次数:" + attackCount);
                }
                player.getCheatTracker().registerOffense(CheatingOffense.MISMATCHING_BULLETCOUNT, "异常的攻击次数.");
                log.info("[作弊] " + player.getName() + " 物理攻击次数异常。 attack.hits " + attack.numDamage + " attackCount " + attackCount + " 技能ID " + attack.skillId);
                if (ServerConstants.isShowGMMessage()) {
                    WorldBroadcastService.getInstance().broadcastGMMessage(MaplePacketCreator.serverNotice(6, "[管理员信息] " + player.getName() + " ID: " + player.getId() + " (等级 " + player.getLevel() + ") 物理攻击次数异常。 attack.hits " + attack.numDamage + " attackCount " + attackCount + " 技能ID " + attack.skillId));
                }
                return false;
            }
        }

        /* 如果当前攻击的伤害数量大于0且攻击次数大于0 */
        if (attack.numDamage > 0 && attack.numAttacked > 0) {
            // 检查当前角色武器的耐久度
            if (!player.getStat().checkEquipDurabilitys(player, -1)) {
                player.dropMessage(5, "武器耐久度不足，无法进行攻击！");
                return false;
            }
        }

        return true;
    }
}
